#include "http.h"
#include <cstring>

namespace MYHTTP 
{

//将字符串方法名转成HTTP方法枚举
HttpMetHod StringToHttpMethod(const std::string& m)
{
#define XX(num, name, string)           \
    if(strcmp(#string, m.c_str()) == 0) \
    {                                   \
        return HttpMetHod::name;        \
    }
    HTTP_METHOD_MAP(XX);
#undef XX

    return HttpMetHod::INVALID_METHOD;
}

//将字符串指针转换成HTTP方法枚举
HttpMetHod CharsToHttpMethod(const char* m)
{
#define XX(num, name, string)                         \
    if(strncmp(#string, m, strlen(#string)) == 0)     \
    {                                                 \
        return HttpMetHod::name;                      \
    }       
    HTTP_METHOD_MAP(XX);
#undef XX

    return HttpMetHod::INVALID_METHOD; 
}

//将http请求码字符串插入到s_method_string
static const char* s_method_string[] = {
#define XX(num, name, string) #string,
    HTTP_METHOD_MAP(XX)
#undef XX
};

//将HTTP方法枚举转换成字符串
const char* HttpMethodToString(const HttpMetHod& m)
{
    uint32_t idx = (uint32_t)m;
    if(idx >= (sizeof(s_method_string) / sizeof(s_method_string[0])))
    {
        return "<unknown>";
    }
    return s_method_string[idx];
}

//将HTTP状态枚举转换成字符串
const char* HttpStatusToString(const HttpStatus& s)
{
    switch(s)
    {
#define XX(num, name, string)                 \
    case HttpStatus::name: return #string;    
    HTTP_STATUS_MAP(XX);
#undef XX
    default: 
        break;
    }

    return "<unknown>";
}

bool CaseInsensitiveLess::operator()(const std::string &lhs, const std::string &rhs) const
{
    //小于0时：	lhs 小于 rhs
    return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
}

//============================ HttpRequest =================================

//版本  是否keepalive保持连接
HttpRequest::HttpRequest(uint8_t version, bool close)
:m_method(HttpMetHod::GET)
,m_version(version)
,m_close(close)
,m_webSocket(false)
,m_parserParamFlag(0)
,m_path("/")
{
}

std::string HttpRequest::getHeader(const std::string& key, const std::string& def) const
{
    auto it = m_headers.find((key));
    return it == m_headers.end() ? def : it->second;
}
std::string HttpRequest::getParam(const std::string& key, const std::string& def) const
{
    // initQueryParam();
    // initBodyParam();
    auto it = m_params.find(key);
    return it == m_params.end() ? def : it->second;
}
std::string HttpRequest::getCookie(const std::string& key, const std::string& def) const
{
    // initCookies();
    auto it = m_cookies.find(key);
    return it == m_cookies.end() ? def : it->second;
}

void HttpRequest::setHeader(const std::string& key, const std::string& val)
{
    m_headers[key] = val;
}
void HttpRequest::setParam(const std::string& key, const std::string& val)
{
    m_params[key] = val;
}
void HttpRequest::setCookie(const std::string& key, const std::string& val)
{
    m_cookies[key] = val;
}

void HttpRequest::delHeader(const std::string& key)
{
    m_headers.erase(key);
}
void HttpRequest::delParam(const std::string& key)
{
    m_params.erase(key);
}
void HttpRequest::delCookie(const std::string& key)
{
    m_cookies.erase(key);
}

bool HttpRequest::hasHeader(const std::string& key, std::string* val)
{
    auto it = m_headers.find(key);
    if(it == m_headers.end())
    {
        return false;
    }
    if(val)
    {
        *val = it->second;
    }
    return true;
}
bool HttpRequest::hasParam(const std::string& key, std::string* val)
{
    // initQueryParam();
    // initBodyParam();
    auto it = m_params.find(key);
    if(it == m_params.end()) 
    {
        return false;
    }
    if(val) 
    {
        *val = it->second;
    }
    return true;
}
bool HttpRequest::hasCookie(const std::string& key, std::string* val)
{
    // initCookies();
    auto it = m_cookies.find(key);
    if(it == m_cookies.end()) 
    {
        return false;
    }
    if(val) 
    {
        *val = it->second;
    }
    return true;
}

std::ostream& HttpRequest::dump(std::ostream& os) const
{
    //GET /uri HTTP/1.1
    //Host: wwww.baidu.com
    os << HttpMethodToString(m_method) << " "   //http方法
       << m_path                                  //请求资源的路径
       << (m_query.empty() ? "" : "?")            //请求参数
       << m_query
       << (m_fragment.empty() ? "" : "#")         //请求fragment
       << m_fragment
       << " HTTP/"
       << ((uint32_t)(m_version >> 4))            
       << "."
       << ((uint32_t)(m_version & 0x0F))
       << "\r\n"; 
    if(!m_webSocket) {
        os << "connection: " << (m_close ? "close" : "keep-alive") << "\r\n";
    }
    for(auto& i : m_headers) {
        if(!m_webSocket && strcasecmp(i.first.c_str(), "connection") == 0) {
            continue;   //不需要重复输出connection
        }
        os << i.first << ": " << i.second << "\r\n";
    }

    if(!m_body.empty()) {
        os << "content-length: " << m_body.size() << "\r\n\r\n"
           << m_body;
    } else {
        os << "\r\n";
    }
    return os;
}
std::string HttpRequest::toString() const
{
    std::stringstream oss;
    dump(oss);
    return oss.str();
}

void HttpRequest::init()
{
    
}
void HttpRequest::initParam()
{
    
}
void HttpRequest::initQueryParam()
{
    
}
void HttpRequest::initBodyParam()
{
    
}
void HttpRequest::initCookies()
{
    
}
//============================ HttpRequest =================================



//============================ HttpResponse =================================
HttpResponse::HttpResponse(uint8_t version, bool close)
:m_status(HttpStatus::OK)
,m_version(version)
,m_close(close)
,m_webSocket(false)
{
}

//获取响应参数
std::string HttpResponse::getHeader(const std::string& key, const std::string& def) const
{
    auto it = m_headers.find(key);
    return it == m_headers.end() ? def : it->second;
}

//设置响应头部参数
void HttpResponse::setHeader(const std::string& key, const std::string& val)
{
    m_headers[key] = val;
}

//删除响应头部参数
void HttpResponse::delHeader(const std::string& key)
{
    m_headers.erase(key);
}

/*
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 9508
Content-Type: text/html
Date: Fri, 27 Oct 2023 08:11:45 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Pragma: no-cache
...
*/
std::ostream& HttpResponse::dump(std::ostream& os) const
{
    os << "HTTP/"
       << ((uint32_t)(m_version >> 4))
       << "."
       << ((uint32_t)(m_version & 0x0F))
       << " "
       << (uint32_t)m_status
       << " "
       << (m_reason.empty() ? HttpStatusToString(m_status) : m_reason)
       << "\r\n";

    for(auto& i: m_headers) // 响应头部MAP
    {
        if(!m_webSocket && strcasecmp(i.first.c_str(), "connection") == 0) 
        {
            continue;
        }
        os << i.first << ": " << i.second << "\r\n";
    }
    for(auto& i : m_cookies) 
    {
        os << "Set-Cookie: " << i << "\r\n";
    }
    if(!m_webSocket) 
    {
        os << "connection: " << (m_close ? "close" : "keep-alive") << "\r\n";
    }
    if(!m_body.empty()) 
    {
        os << "content-length: " << m_body.size() << "\r\n\r\n"
           << m_body;
    } else 
    {
        os << "\r\n";
    }
    return os;
}
std::string HttpResponse::toString() const
{
    std::stringstream oss;
    dump(oss);
    return oss.str();
}

//设置重定向
void HttpResponse::setRedirect(const std::string& uri)
{
    m_status = HttpStatus::FOUND;
    setHeader("Location", uri);
}
void HttpResponse::setCookie(const std::string& key, const std::string& val,
                time_t expired, const std::string& path,
                const std::string& domain, bool secure)
{
    
}
//============================ HttpResponse =================================


//流式输出HttpRequest
std::ostream& operator<<(std::ostream& os, const HttpRequest& req)
{
    return req.dump(os);
}

//流式输出HttpResponse
std::ostream& operator<<(std::ostream& os, const HttpResponse& rsp)
{
    return rsp.dump(os);
}

}   //MYHTTP

